/*
 Created by hgy on 2020/02/05
 */

(function (App) {
    'use strict';

    var module = App.module("flowBoard");

    /*
    *
    * 流程图绘制--流程面板
    *
    * */

    Vue.component('flow-panel', {
        template:
            '<div class="flowPanel" v-if="easyFlowVisible" ' +
            ':class="nodeData.preview?\'preview\':\'\'">' +
                '<flow-menu @addNode="addNode" v-if="!(nodeData.preview)"></flow-menu>'+
                '<div class="flowCanvas" ref="flowCanvas">' +
                    '<div :id="containerId" class="container" :class="lineCorrect" ref="moveCanvas" v-moveThis>' +
                        '<p class="horizontalLine" v-if="HLineShow" :style="{top: HLineTop}"></p>' +
                        '<p class="verticalLine" v-if="VLineShow" :style="{left: VLineLeft}"></p>' +
                        '<template v-for="(node,index) in flowData.nodeList">' +
                            '<flow-node v-show="!node.delete" :id="node.id" :node="node" :nodeIndex="index" :preview="nodeData.preview"' +
                                '@choosedComp="choosedComp"' +
                                '@deleteNode="deleteNode"' +
                                '@changeNodeSite="changeNodeSite">' +
                            '</flow-node>'+
                        '</template>' +
                    '</div>' +
                '</div>' +
            '</div>',
        props: {
            nodeData: {
                type: Object,
                required: true,
            },
            containerId: {
                type: String,
                required: true
            },
            isEdit: {
                type: Boolean
            }
        },
        computed: {
            lineCorrect() {
                var lineClassName = {};
                lineClassName['hlineCorrect'] = this.HlineCorrect;
                lineClassName["vlineCorrect"] = this.VlineCorrect;
                return lineClassName;
            }
        },
        data: function () {
            return {
                // jsPlumb 实例
                jsPlumb: null,
                easyFlowVisible: true,
                // 控制流程数据显示与隐藏
                flowInfoVisible: false,
                // 控制表单显示与隐藏
                nodeFormVisible: false,
                // 默认设置参数
                jsplumbSetting: {
                    // 动态锚点、位置自适应
                    // Anchors: ['Top', 'TopCenter', 'TopRight', 'TopLeft', 'Right', 'RightMiddle', 'Bottom', 'BottomCenter', 'BottomRight', 'BottomLeft', 'Left', 'LeftMiddle'],
                    Container: this.containerId,
                    // 连线的样式 StateMachine、Flowchart
                    Connector: ['Flowchart', { stub: [0, 0], gap: 5, cornerRadius: 5, alwaysRespectStubs: false }],
                    // 鼠标不能拖动删除线
                    ConnectionsDetachable: false,
                    // 删除线的时候节点不删除
                    DeleteEndpointsOnDetach: false,
                    // 连线的端点
                    Endpoint: ["Dot", {radius: 5}],
                    // Endpoint: ["Rectangle", {height: 10, width: 10}],
                    // 线端点的样式
                    EndpointStyle: {fill: 'rgba(255,255,255,0)', outlineWidth: 1},
                    LogEnabled: true,//是否打开jsPlumb的内部日志记录
                    // 绘制线
                    PaintStyle: {stroke: '#666', strokeWidth: 1},
                    // 绘制箭头
                    Overlays: [['Arrow', {width: 8, length: 6, location: 1}]],
                    RenderMode: "svg"
                },
                // jsplumb连接参数
                jsplumbConnectOptions: {
                    isSource: true,
                    isTarget: true,
                    // 动态锚点、提供了4个方向 Continuous、AutoDefault
                    anchor: "Continuous",
                },
                jsplumbSourceOptions: {
                    /*"span"表示标签，".className"表示类，"#id"表示元素id*/
                    filter: ".flow-node-drag",
                    filterExclude: false,
                    anchor: "Continuous",
                    allowLoopback: false
                },
                jsplumbTargetOptions: {
                    /*"span"表示标签，".className"表示类，"#id"表示元素id*/
                    filter: ".flow-node-drag",
                    filterExclude: false,
                    anchor: "Continuous",
                    allowLoopback: false
                },
                // 是否加载完毕
                loadEasyFlowFinish: false,
                // 数据
                flowData: {
                    preview: true,
                    nodeList:[],
                    lineList:[]
                },
                currentNode: {},
                HLineShow: false,   // 水平较量线
                VLineShow: false,   // 垂直较量线
                HLineTop: 0,
                VLineLeft: 0,
                HlineCorrect: false,
                VlineCorrect: false,
            }
        },
        mounted() {
            this.jsPlumb = jsPlumb.getInstance();
            var _that = this;
            this.$nextTick(function()  {
                this.jsPlumbInit(_that);
            });
        },
        methods: {
            jsPlumbInit(_that) {
                _that.jsPlumb.ready(function() {
                    // 导入默认配置
                    _that.jsPlumb.importDefaults(_that.jsplumbSetting);
                    // 会使整个jsPlumb立即重绘。
                    _that.jsPlumb.setSuspendDrawing(false, true);
                    // 初始化节点
                    _that.loadEasyFlow();
                    // 单点击了连接线,
                    _that.jsPlumb.bind('click', function(conn, originalEvent) {
                        if(_that.flowData.preview) return;
                        _that.$confirm('确定删除所点击的线吗?', '提示', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        }).then(function() {
                            _that.jsPlumb.deleteConnection(conn)
                        }).catch(function() {});
                    });
                    // 连线
                    _that.jsPlumb.bind("connection", function(evt) {
                        var from = evt.source.id;
                        var to = evt.target.id;
                        if (_that.loadEasyFlowFinish) {
                            _that.flowData.lineList.push({from: from, to: to})
                        }
                    });

                    // 删除连线回调
                    _that.jsPlumb.bind("connectionDetached", function(evt) {
                        _that.deleteLine(evt.sourceId, evt.targetId);
                    });

                    // 改变线的连接节点
                    _that.jsPlumb.bind("connectionMoved", function(evt){
                        _that.changeLine(evt.originalSourceId, evt.originalTargetId);
                    });

                    // contextmenu
                    _that.jsPlumb.bind("contextmenu", function(evt){
                        console.log('contextmenu', evt);
                    });

                    // 连线
                    _that.jsPlumb.bind("beforeDrop", function(evt){
                        var from = evt.sourceId;
                        var to = evt.targetId;
                        if (from === to) {
                            _that.$message.error('不能连接自己');
                            return false;
                        }
                        if (_that.hasLine(from, to)) {
                            _that.$message.error('不能重复连线');
                            return false;
                        }
                        if (_that.hashOppositeLine(from, to)) {
                            _that.$message.error('不能回环');
                            return false;
                        }
                        _that.$message({
                            message: '连线成功',
                            type: 'success'
                        });
                        return true;
                    });

                    // beforeDetach
                    _that.jsPlumb.bind("beforeDetach", function(evt){
                        // console.log('beforeDetach', evt);
                    });
                })
            },
            // 加载流程图
            loadEasyFlow() {
                var _that = this;
                var nodeStatusObj = {};
                var endProId = '';
                var minLeft = 1000;
                var maxRight = 0;
                var compWidth = {startPro: 30, endPro:30, processNode: 120};
                if(this.flowData.nodeList && this.flowData.nodeList.length>=1){
                    this.flowData.nodeList.forEach(function (node) {
                        nodeStatusObj[node.id] = !node.nodeStatus ? '#666' : '#759BEA' ;
                        node.type == 'endPro' ? endProId= node.id : false;
                        var nodeLeft = parseInt(node.left);
                        var nodeRight = nodeLeft + compWidth[node.type]
                        if(nodeRight>maxRight){
                            maxRight = nodeRight;
                        }
                        if(nodeLeft<minLeft){
                            minLeft = nodeLeft;
                        }
                        // 设置源点，可以拖出线连接其他节点
                        _that.jsPlumb.makeSource(node.id, _that.jsplumbSourceOptions);
                        // // 设置目标点，其他源点拖出的线可以连接该节点
                        _that.jsPlumb.makeTarget(node.id, _that.jsplumbTargetOptions);

                        if(!_that.nodeData.preview){
                            _that.jsPlumb.draggable(node.id, {
                                containment: 'parent',
                                drag: function (event) {
                                    _that.dragSiteChange(event.el,event.pos[0],event.pos[1]);
                                    event.el.className = event.el.className + ' dragNodeStyle';
                                    _that.jsPlumb.repaintEverything();
                                },
                                stop: function (event) {
                                    _that.jsPlumb.repaintEverything();
                                    event.el.className = event.el.className.replace('dragNodeStyle','');
                                    _that.HLineShow = false;
                                    _that.VLineShow = false;
                                }
                            });
                        }
                    });
                    var  flowCanvasWidth = _that.$refs.flowCanvas.clientWidth;
                    if(maxRight-minLeft < flowCanvasWidth){
                        this.$refs.moveCanvas.style.left = parseInt((flowCanvasWidth - (maxRight-minLeft))/2 - 20) + 'px';
                    }
                }

                // 初始化连线
                if(this.flowData.lineList && this.flowData.lineList.length>=1){
                    if(!_that.flowData.preview){
                        this.flowData.lineList.forEach(function (line) {
                            _that.jsPlumb.connect({
                                source: line.from,
                                target: line.to,
                            }, _that.jsplumbConnectOptions);
                        });
                    }else{
                        this.flowData.lineList.forEach(function (line) {
                            var strokeColor = '#E6ECF7';
                            if(endProId == line.to){
                                strokeColor = nodeStatusObj[line.from];
                            }else{
                                strokeColor = nodeStatusObj[line.to];
                            }
                            _that.jsPlumb.connect({
                                source: line.from,
                                target: line.to,
                                paintStyle: { stroke: strokeColor, strokeWidth: 1 }
                            }, _that.jsplumbConnectOptions);
                        });
                    }
                }

                this.$nextTick(function () {
                    this.loadEasyFlowFinish = true;
                })
            },
            // 删除线
            deleteLine(from, to) {
                this.flowData.lineList = this.flowData.lineList.filter(function (line) {
                    if (line.from == from && line.to == to) {
                        return false;
                    }
                    return true;
                })
            },
            // 改变连线
            changeLine(oldFrom, oldTo) {
                this.deleteLine(oldFrom, oldTo);
            },

            // 改变节点的位置
            dragSiteChange(nodeEl,leftSite,topSite) {
                var _that = this;
                var HlineCorrect = false;
                var VlineCorrect = false;
                var newLeftSite = leftSite + nodeEl.offsetWidth/2,
                    newTopSite = topSite + nodeEl.offsetHeight/2;
                this.flowData.nodeList.forEach(function (node) {
                    var compHalfHeight = node.type == "processNode"?33:15,
                        compHalfWidth = node.type == "processNode"?60:15;
                    var newNodeTop = parseInt(node.top) + compHalfHeight,
                        newNodeleft = parseInt(node.left) + compHalfWidth;
                    if(node.id != nodeEl.id){
                        if(Math.abs(newNodeTop - newTopSite)<5){
                            _that.HLineShow = true;
                            _that.HLineTop = newNodeTop+'px';
                        }
                        if(newNodeTop == newTopSite){
                            _that.HlineCorrect = true;
                            HlineCorrect = true;
                        }
                        if(Math.abs(newNodeleft - newLeftSite)<5){
                            _that.VLineShow = true;
                            _that.VLineLeft = newNodeleft+'px';
                        }
                        if(newNodeleft == newLeftSite){
                            _that.VlineCorrect = true;
                            VlineCorrect = true;
                        }
                    }
                });
                _that.HlineCorrect = HlineCorrect;
                _that.VlineCorrect = VlineCorrect;
            },

            // 改变节点的位置
            changeNodeSite(data) {
                for (var i = 0; i < this.flowData.nodeList.length; i++) {
                    var node = this.flowData.nodeList[i];
                    node.checked = false;
                    if (node.id === data.id) {
                        node.checked = true;
                        node.left = data.left;
                        node.top = data.top;
                    }
                }
            },


            /**
             * 选中当前编辑节点
             * @param nodeId 被点击编辑的节点的ID
             */
            choosedComp(nodeData) {
                var _that = this;
                if(!_that.currentNode.id || nodeData.id != _that.currentNode.id){
                    _that.currentNode = nodeData.node;
                    _that.flowData.nodeList.forEach(function (node) {
                        node.checked = node.id == nodeData.id;
                    });
                    _that.$emit("changeNode",nodeData.node);
                    if(this.isEdit){
                        _that.$confirm('节点信息未保存，是否保存?', '提示', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        }).then(function() {
                            _that.$emit("saveNode");
                        }).catch(function() {
                            App.eventBus.fire('isEdit', false);
                        });
                    }
                }
            },


            // 获取指定id节点数据
            getNodeData(nodeId){
                var nodeData = {};
                var _that = this;
                _that.flowData.nodeList.forEach(function (node) {
                    if (node.nodeId == nodeId) {
                        Object.assign(nodeData, node);
                    }
                });
                return nodeData;
            },

            // 修改指定id节点数据
            editNodeData(nodeId, nodeData){
                var _that = this;
                _that.flowData.nodeList = _that.flowData.nodeList.map(function (node, index) {
                    if(node.nodeId == nodeId){
                        // 如果状态修改，修改其连接颜色
                        if(node.nodeStatus != nodeData.nodeStatus){
                            _that.setLineStyle(node.id, nodeData);
                        }
                        return nodeData;
                    }else{
                        return node;
                    }
                });
            },

            // 修改连线颜色
            setLineStyle(nodeId, nodeData){
                var _that = this;
                this.jsPlumb.getConnections().forEach(function (line) {
                    if(line.targetId == nodeId){
                        var LineColor = !nodeData.nodeStatus ? '#666' : '#759BEA';
                        line.setPaintStyle({stroke: LineColor});
                        if(nodeData.nodeStatus == 'start'){
                            line.canvas.style.animation = "dash 15s linear infinite";
                        }else{
                            line.canvas.style.animation = 'none';
                        }

                    }
                    if(line.source.textContent == "开始" && line.targetId == nodeId){
                       if(!nodeData.nodeStatus) {
                           line.source.style.borderColor = '#666';
                       } else {
                           line.source.style.borderColor = '#5786EA';
                       }
                    }
                    if(line.target.textContent == "结束" && line.sourceId == nodeId){
                        if(!nodeData.nodeStatus || nodeData.nodeStatus == 'start') {
                            line.setPaintStyle({stroke: '#666'});
                            line.target.style.borderColor = '#666';
                        } else {
                            line.setPaintStyle({stroke: '#759BEA'});
                            line.target.style.borderColor = '#5786EA';

                        }
                    }
                });
            },

            /**
             * 拖拽结束后添加新的节点
             * @param evt
             * @param nodeMenu 被添加的节点对象
             * @param initialPoint 鼠标初始位置
             *
             */
            addNode(evt, initialPoint, nodeMenu) {
                var deviateleft = evt.clientX - 106 - initialPoint.left ;
                var deviatetop = evt.clientY - 113 - initialPoint.top;
                if(deviateleft<0 || deviatetop<0){
                    return false;
                }
                var nodeId = this.flowData.boardId + this.randomString(6);
                var node = {
                    id: nodeId,
                    nodeId: nodeId,
                    boardId: this.flowData.boardId,
                    compClassName: nodeMenu.compClassName,
                    type: nodeMenu.type,
                    nodeName: nodeMenu.nodeName,
                    left: deviateleft,
                    top: deviatetop,
                    checked: false,
                    isNew: true
                };
                this.flowData.nodeList.push(node);
                var _that = this;
                this.$nextTick(function () {
                    this.choosedComp({node: node, id: nodeId});
                    this.$emit('addNode',node);
                    this.$emit("changeNode",node);
                    this.jsPlumb.makeSource(nodeId, this.jsplumbSourceOptions);
                    this.jsPlumb.makeTarget(nodeId, this.jsplumbTargetOptions);
                    this.jsPlumb.draggable(nodeId, {
                        containment: 'parent',
                        drag: function (event) {
                            _that.dragSiteChange(event.el,event.pos[0],event.pos[1]);
                            event.el.className = event.el.className + ' dragNodeStyle';
                            _that.jsPlumb.repaintEverything();
                        },
                        stop: function (event) {
                            _that.jsPlumb.repaintEverything();
                            event.el.className = event.el.className.replace('dragNodeStyle','');
                            _that.HLineShow = false;
                            _that.VLineShow = false;
                        }
                    })
                })
            },

            /**
             * 删除节点
             * @param nodeId 被删除节点的ID
             */
            deleteNode(nodeId) {
                var _that = this;
                this.$confirm('确定删除当前节点?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning',
                    closeOnClickModal: false
                }).then(function()  {
                    hexui.forEach(_that.flowData.nodeList,function (node) {
                        if(node.id == nodeId){
                            _that.$emit('delNode',node);
                        }
                    });
                }).catch(function()  {});
                return true;
            },

            afterDelNode(nodeId){
                var _that = this;
                hexui.forEach(_that.flowData.nodeList,function (node) {
                    if(node.id == nodeId){
                        node.delete = true;
                    }
                });
                _that.$nextTick(function () {
                    _that.jsPlumb.remove(nodeId); // jsPlumb删除节点
                    _that.jsPlumb.removeAllEndpoints(nodeId);
                })

            },

            // 产生随机数
            randomString(len) {
                len = len || 32;
                var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
                var maxPos = $chars.length;
                var result = '';
                for (var i = 0; i < len; i++) {
                    result += $chars.charAt(Math.floor(Math.random() * maxPos));
                }
                return result;
            },

            // 是否具有该线
            hasLine(from, to) {
                for (var i = 0; i < this.flowData.lineList.length; i++) {
                    var line = this.flowData.lineList[i];
                    if (line.from === from && line.to === to) {
                        return true
                    }
                }
                return false
            },
            // 是否含有相反的线
            hashOppositeLine(from, to) {
                return this.hasLine(to, from)
            },


            // 加载流程图
            dataReload(data,fun) {
                var _this = this;
                this.easyFlowVisible = false;
                this.flowData.nodeList = [];
                this.flowData.lineList = [];
                this.currentNode = {};
                this.$nextTick(function() {
                    data = JSON.parse(JSON.stringify(data));
                    _this.easyFlowVisible = true;
                    _this.flowData = data;
                    this.$nextTick(function()  {
                        _this.jsPlumb = jsPlumb.getInstance();
                        this.$nextTick(function()  {
                            _this.jsPlumbInit(_this);
                            !!fun?fun():false;
                        });
                    });
                });
            }
        }

    });
})(window.App);